import {pathJoin} from "./PathUtils";
import {httpUtils} from "./HttpUtils";
import LimitPromise from "../utils/LimitPromise";
import parse from "postcss/lib/parse";
import stringify from "postcss/lib/stringify";
import {SFCBlock} from "vue-template-compiler";

const css = {} // 缓存
const urlLimit: { [key: string]: LimitPromise<string> } = {}

function xhr(url: string): Promise<string> {
  if (!urlLimit[url]) {
    urlLimit[url] = new LimitPromise<string>(1)
  }
  return urlLimit[url].call(() => {
    return new Promise(resolve => {
      if (css[url]) {
        resolve(css[url])
      } else {
        httpUtils(url)
          .then(cssText => {
            css[url] = cssText
            delete urlLimit[url]
            return cssXhr(url, cssText)
          })
          .then(res => {
            resolve(res)
          })
          .catch(e => {
            console.error(e)
            resolve('')
          })
      }
    })
  })
}

export function cssXhr(baseUrl: string, content: string) {
  return new Promise<string>(resolve => {
    if (content) {
      const strings = content.split('\n'); // 采用\n分隔
      const replaceList: [number, Promise<string>][] = []
      for (let i = 0; i < strings.length; i++) {
        const item = strings[i]
        if (item.startsWith('@import "')) { // 判断是不是要请求的
          // 解析出url
          let url = item.replace('@import "', '').replace('";', '')
          url = pathJoin(baseUrl, url)
          replaceList.push([i, xhr(url)])
        }
      }
      const proList: Promise<string>[] = replaceList.map(i => i[1])
      Promise.all(proList)
        .then(res => {
          for (let i = 0; i < res.length; i++) {
            strings[replaceList[i][0]] = res[i] + '\n'
          }
          resolve(strings.join('\n'))
        })
        .catch(e => {
          resolve('')
          console.error(e)
        })
    } else {
      resolve('')
    }
  })
}


export function rewriteSelector(selector: string, scopedId: string): string {
  const deep = ['::v-deep', '>>>', '/deep/']

  // .test:hover
  function addScopedId(add: string) {
    if (add.includes(':')) {
      const strings = add.split(':');
      strings[0] += `[${scopedId}]`
      return strings.join(':')
    }
    add += `[${scopedId}]`
    return add
  }

  // .project .projectSpecial, .project .projectWork
  // ,前面也要添加 解决继承样式不生效问题
  if (selector.includes(',')) {
    const strings = selector.split(',');
    return strings.map(i => rewriteSelector(i, scopedId)).join(',')
  }

  const split = selector.split(' ');
  if (split.length === 1) {
    if (deep.includes(split[0])) {
      return split.join(' ')
    }
    split[0] = addScopedId(split[0])
    return split.join(' ')
  }
  const findIndex = split.findIndex(i => deep.includes(i))
  if (findIndex === -1) {
    split[split.length - 1] = addScopedId(split[split.length - 1])
    return split.join(' ')
  }
  if (findIndex === 0) {
    return split.slice(1).join(' ')
  }
  if (findIndex > 0) {
    split[findIndex - 1] = addScopedId(split[findIndex - 1])
    split.splice(findIndex, 1)
    return split.join(' ')
  }
  return selector
}

export interface Px2Rem {
  run: boolean;
  base: number;
}

export const px2Rem: Px2Rem = { // 只把px转为rem，PX，pX，Px都不转，只转style中的
  run: false,
  base: 12
}

/**
 * 配置px转rem
 * @param run
 * @param base
 * @private
 */
export function configPx2Rem(run = false, base = 12) {
  px2Rem.run = run
  px2Rem.base = base
}


export function rewriteDecl(baseUrl: string, decl: string, px2Rem: Px2Rem): string {
  if (px2Rem.run) {
    decl = decl.replace(/^((\d+)|((\d+)?\.\d+))px$/, ($0, $1) => {
      if ($1) {
        const num = Number($1) / px2Rem.base
        return num + 'rem'
      } else {
        return $0
      }
    })
  }
  // url("./img/多边形 ")2.png")
  // background: url("./../img/多边形 2.png") no-repeat scroll 1.2rem center transparent;
  decl = decl.replace(/url\("(.*)"\)/, ($0, $1) => {
    if ($1) {
      return `url("${pathJoin(baseUrl, $1)}")`
    } else {
      return $0;
    }
  })
  return decl
}

const globalCss = {}

/**
 *
 * @param lang
 * @param content
 */
export function addGlobalCss(lang: string, content: string) {
  globalCss[lang] = content
}

export type cssRenderFunc = (style: string, call: (css: string) => void) => void

const cssRender: { [key: string]: cssRenderFunc } = {}

export function addCssRender(key, func: cssRenderFunc) {
  cssRender[key] = func
}


export function addCssToHead(css: string, scoped = false, scopedId: string, baseUrl: string) {
  if (scoped && scopedId) {
    const root = parse(css);

    /**
     * 为 keyframes  添加 scopedId
     */
    function keyframesAddscopedId() {
      const renameMap={} as [string, string]
      // 1. 替换 @keyframes 名称
      root.walkAtRules('keyframes', (atRule) => {
        const oldName = atRule.params.trim();
        atRule.params = oldName+'-'+scopedId;
        renameMap[oldName]=atRule.params
      });
      // 2. 替换 animation 属性中的关键帧引用
      root.walkDecls((decl) => {
        // 匹配 animation 相关属性
        if (decl.prop.match(/^animation(-name)?$/i)) {
          let value = decl.value;
          // 遍历替换列表，替换属性中的旧名称
          Object.entries(renameMap).forEach(([oldName, newName]) => {
            // 用正则匹配完整的动画名称，避免部分匹配
            const reg = new RegExp(`\\b${oldName}\\b`, 'g');
            value = value.replace(reg, newName);
          });
          decl.value = value;
        }
      });
    }

    keyframesAddscopedId()
    root.walkRules((rule, index) => {
      // 排除 keyframes 转换
      if(rule.parent && ['keyframes'].includes(rule.parent.name)) {
        return
      }
      rule.selector = rewriteSelector(rule.selector, scopedId)
    })
    root.walkDecls((decl, index) => {
      decl.value = rewriteDecl(baseUrl, decl.value, px2Rem)
    })
    css = ''
    stringify(root, (str) => {
      css += str
    })
  }
  const head = document.head || document.getElementsByTagName('head')[0]
  const styleElement = document.createElement('style');
  styleElement.innerHTML = css
  head.appendChild(styleElement)
}

export function getItem(baseUrl, i: SFCBlock, scopedId: string) {
  return cssXhr(baseUrl, i.content).then(css => {
    if (i.lang && i.lang !== 'css') {
      const css1 = cssRender[i.lang];
      if (css1) {
        css1(css, (css) => {
          if (css) {
            addCssToHead(css, i.scoped, scopedId, baseUrl)
          }
        })
      } else {
        console.error(i.lang + window.__chineseTranscode__('不被支持，你需要自己实现或者改用less语法，下面给出一个添加的列子'))
        console.error(`BrowseVueLoader.addCssRender('less', (style, call) => {
  if (style) {
    render(style).then(res => {
      call(res.css)
    })
  }
})`)
      }
    } else {
      addCssToHead(css, i.scoped, scopedId, baseUrl)
    }
  })
}

const limitPromise = new LimitPromise(1)

export function addCssToPage(baseUrl: string, styles: SFCBlock[], scopedId: string) {
  return new Promise(resolve => {
    if (styles.length) {
      for (const i of styles) {
        if (i.src) {
          let newBaseUrl = pathJoin(baseUrl, i.src)
          limitPromise.call(() => {
            return xhr(newBaseUrl).then(content => {
              i.content = content
              if (globalCss[i.lang || 'css']) {
                i.content += (globalCss[i.lang || 'css'] + '\n')
              }
              return getItem(newBaseUrl, i, scopedId)
            })
          })
        } else {
          if (globalCss[i.lang || 'css']) {
            i.content += (globalCss[i.lang || 'css'] + '\n')
          }
          limitPromise.call(() => {
            return getItem(baseUrl, i, scopedId)
          })
        }
      }
      limitPromise.call(() => {
        resolve(undefined)
        return Promise.resolve()
      })
    } else {
      resolve(undefined)
    }
  })
}



